package net.xumf.service.master.impl;

import lombok.extern.slf4j.Slf4j;
import net.xumf.service.master.QuartzService;
import net.xumf.service.master.job.BaseJob;
import net.xumf.support.consts.Constants;
import net.xumf.support.enums.QuartzTriggerState;
import net.xumf.support.model.dto.QuartzDTO;
import net.xumf.support.model.vo.CronTriggerReportVO;
import net.xumf.support.model.vo.CronTriggerVO;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Slf4j
public class QuartzServiceImpl implements QuartzService {

    @Autowired
    private Scheduler scheduler;

    @Override
    public List<CronTriggerVO> getAllJob() throws SchedulerException {
        return scheduler.getJobGroupNames().stream()
                .flatMap(o -> {
                    try {
                        return scheduler.getJobKeys(GroupMatcher.jobGroupEquals(o)).stream();
                    } catch (SchedulerException e) {
                        log.error("定时器错误：{}", e);
                        return null;
                    }
                })
                .flatMap(o -> {
                    try {
                        return scheduler.getTriggersOfJob(o).stream();
                    } catch (SchedulerException e) {
                        log.error("定时器错误：{}", e);
                        return null;
                    }
                })
                .map(o -> CronTriggerVO.builder()
                        .jobName(o.getKey().getName())
                        .description(o.getDescription())
                        .cronExpression(((CronTrigger) o).getCronExpression())
                        .build()).collect(Collectors.toList());
    }

    @Override
    public List<CronTriggerVO> getAllNormalJob() throws SchedulerException {

        return scheduler.getJobKeys(GroupMatcher.jobGroupEquals(Constants.Normal.NORMAL_GROUP_NAME)).stream()
                .flatMap(o -> {
                    try {
                        return scheduler.getTriggersOfJob(o).stream();
                    } catch (SchedulerException e) {
                        log.error("定时器错误：{}", e);
                        return null;
                    }
                })
                .map(o -> {
                    try {
                        return CronTriggerVO.builder()
                                .status(QuartzTriggerState.valueOf(scheduler.getTriggerState(o.getKey()).name()))
                                .cronExpression(((CronTrigger) o).getCronExpression())
                                .jobName(o.getKey().getName())
                                .description(o.getDescription())
                                .jobClassName(scheduler.getJobDetail(o.getJobKey()).getJobClass().getName())
                                .build();
                    } catch (SchedulerException e) {
                        log.error("定时器错误：{}", e);
                        return null;
                    }
                }).collect(Collectors.toList());
    }

    /**
     * <T extends Trigger> 转换 {@link CronTriggerReportVO} 类
     *
     * @param o <T extends Trigger>
     * @return {@link CronTriggerReportVO}
     */
    private <T extends Trigger> CronTriggerReportVO triggerToReportCronTriggerVO(T o) {
        try {
            CronTriggerReportVO vo = new CronTriggerReportVO();
            vo.setReceiver(Optional.ofNullable(o.getJobDataMap().getString("receiver")).orElse(""));
            vo.setUserId(o.getJobDataMap().getLong("userId"));
            vo.setRId(o.getJobDataMap().getInt("rId"));
            vo.setStatus(QuartzTriggerState.valueOf(scheduler.getTriggerState(o.getKey()).name()));
            vo.setReportName(Optional.ofNullable(o.getJobDataMap().getString("reportName")).orElse(""));
            vo.setCronExpression(((CronTrigger) o).getCronExpression());
            vo.setJobName(o.getKey().getName());
            vo.setDescription(o.getDescription());
            return vo;
        } catch (SchedulerException e) {
            log.error("定时器错误：{}", e);
            return null;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public void addNormalJob(QuartzDTO dto) throws SchedulerException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        // 启动调度器
        scheduler.start();
        //构建job信息
        BaseJob job = (BaseJob) Class.forName(dto.getJobClassName()).newInstance();
        JobDetail jobDetail = JobBuilder.newJob()
                .ofType(job.getClass())
                .withIdentity(dto.getJobName(), Constants.Normal.NORMAL_GROUP_NAME)
                .withDescription(dto.getDescription())
                .build();
        //表达式调度构建器(即任务执行的时间)
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(dto.getCronExpression());
        //按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(dto.getJobName(), Constants.Normal.NORMAL_GROUP_NAME)
                .withDescription(dto.getDescription())
                .withSchedule(scheduleBuilder)
                .build();
        scheduler.scheduleJob(jobDetail, trigger);
    }

    @Override
    public void jobPause(String jobName) throws SchedulerException {
        scheduler.pauseJob(JobKey.jobKey(jobName, null));
    }

    @Override
    public void jobPause(String jobName, String group) throws SchedulerException {
        scheduler.pauseJob(JobKey.jobKey(jobName, group));
    }

    @Override
    public void jobResume(String jobName) throws SchedulerException {
        jobResume(jobName, null);
    }

    @Override
    public void jobResume(String jobName, String group) throws SchedulerException {
        scheduler.resumeJob(JobKey.jobKey(jobName, group));
    }

    @Override
    public void jobNormalReschedule(QuartzDTO dto) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(dto.getJobName(), Constants.Normal.NORMAL_GROUP_NAME);
        // 表达式调度构建器
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(dto.getCronExpression());
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        // 按新的cronExpression表达式重新构建trigger
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                .withDescription(dto.getDescription())
                .withSchedule(scheduleBuilder)
                .build();
        // 按新的trigger重新设置job执行
        scheduler.rescheduleJob(triggerKey, trigger);
    }

    @Override
    public void jobDelete(String jobName) throws SchedulerException {
        jobDelete(jobName, null);
    }

    @Override
    public void jobDelete(String jobName, String group) throws SchedulerException {
        scheduler.pauseTrigger(TriggerKey.triggerKey(jobName, group));
        scheduler.unscheduleJob(TriggerKey.triggerKey(jobName, group));
        scheduler.deleteJob(JobKey.jobKey(jobName, group));
    }

}